package loja;

import helpers.Categoria;
import helpers.Logger;
import interfaces.ClienteInterface;
import interfaces.ProdutoInterface;
import interfaces.ServerInterface;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.sql.Date;
import java.sql.SQLException;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
import java.util.TreeMap;
import java.util.TreeSet;

import exceptions.ClienteErroLoginException;
import exceptions.ClienteJaExistenteException;
import exceptions.ClienteNaoEncontradoException;
import exceptions.CreditoInsuficienteException;
import exceptions.ProdutoJaExistenteException;

public class Servidor extends Observable implements ServerInterface,
		Serializable {

	private static final long serialVersionUID = 1L;

	/**
	 * Recupera a quantidade de produtos data uma determinada categoria; return
	 * inteiro quantidade de produtos entrada Categoria para ser verificada
	 */
	public int quantidadeProdutosCategoria(Categoria c) throws RemoteException {
		return Produto.getQuantidadeByCategoria(c);
	}

	/**
	 * Remove um produto do carrinho deve ser inforado o produto e a quantidade
	 */
	public void removeAoCarrinho(ProdutoInterface p, int quantidade)
			throws RemoteException {
		Produto produto = (Produto) p;
		produto.adicionaQuantidadeCarrinho(quantidade);
	}

	/**
	 * Recupera um Cliente pelo seu Login gera excecao caso o cliente nao exista
	 * ou se o login informado estiver errado
	 */
	public Cliente getClienteByLogin(String login, String passwd)
			throws RemoteException, ClienteNaoEncontradoException,
			ClienteErroLoginException {
		Logger.loginCliente(login);
		return Cliente.getClienteByLogin(login, passwd);
	}

	public Cliente getClienteByLogin(String login) throws RemoteException,
			ClienteNaoEncontradoException, ClienteErroLoginException {
		return Cliente.getClienteByLogin(login);
	}

	/**
	 * Busca produtos pelo nome Retorna um treeset dos produtos ordenados pelo
	 * ordenador que foi recebido pelo m�todo deve passar o comparador,
	 * apartir de qual entrada no banco o cliente deseja recuperar, quantos
	 * produtos deseja recuperar e o nome para usar na busca
	 */
	public TreeSet<ProdutoInterface> getProdutosByNome(
			Comparator<ProdutoInterface> c, int primeiro, int quantidade,
			String nome) throws RemoteException {
		return Produto.getProdutosByNome(c, primeiro, quantidade, nome);
	}

	/**
	 * Recupera produtos no banco
	 * 
	 * @param comparator
	 *            - para usar no treeset de retorno
	 * @param primeiro
	 *            - apartir de qual entrada no banco deve-se comecar a retornar
	 * @param quantidade
	 *            - quantos produtos devem ser retornados
	 * @param cat
	 *            - categoria a ser buscada
	 * @param fabricante
	 *            - fabricante a ser buscado
	 * @return - treeset com os produtos ordenados pelo comparator
	 * @throws RemoteException
	 */
	public TreeSet<ProdutoInterface> getProdutosByCategoriaFabricante(
			Comparator<ProdutoInterface> comparator, int primeiro,
			int quantidade, Categoria cat, String fabricante)
			throws RemoteException {
		return Produto.getProdutosByCategoriaFabricante(comparator, primeiro,
				quantidade, cat, fabricante);
	}

	/**
	 * Adiciona um produto no carrinho
	 * 
	 * @param p
	 *            - produto a ser adicionado
	 * @param quantidade
	 *            - quantidade a ser adicionada
	 * @throws RemoteException
	 */
	public void adicionaAoCarrinho(ProdutoInterface p, int quantidade)
			throws RemoteException {
		Produto produto = (Produto) p;
		produto.retiraQuantidadeCarrinho(quantidade);
	}

	/**
	 * Esvaziar carrinho. Devolve todos os produtos do carrinho
	 * 
	 * @param a
	 *            - TreeMap carrinho
	 * @return - true se conseguiu todos
	 */
	public boolean esvaziarCarrinho(TreeMap<ProdutoInterface, Integer> a)
			throws RemoteException {
		Iterator<ProdutoInterface> itr = a.keySet().iterator();
		boolean conseguiuTodos = true;
		while (itr.hasNext()) {
			ProdutoInterface p = itr.next();
			Produto produto = (Produto) p;
			boolean b = produto.adicionaQuantidadeCarrinho(a.get(p));
			if (!b) {
				conseguiuTodos = false;
			}
		}

		return conseguiuTodos;
	}

	/**
	 * Retira um produto do carrinho
	 * 
	 * @param p
	 *            - produto a ser retirado
	 * @param quantidade
	 *            - quantidade a ser retirada
	 * @return - true se sucesso
	 * @throws RemoteException
	 */
	public boolean removeProdutoCarrinho(ProdutoInterface p, int quantidade)
			throws RemoteException {
		Produto produto = (Produto) p;
		return produto.adicionaQuantidadeCarrinho(quantidade);
	}

	/**
	 * Cria um novo cliente
	 * 
	 * @param nome
	 * @param email
	 * @param login
	 * @param passwd
	 * @param cpf
	 * @param telefone
	 * @param rua
	 * @param numero
	 * @param cep
	 * @param credito
	 * @return
	 * @throws ClienteJaExistenteException
	 */
	public Cliente adicionarCliente(String nome, String email, String login,
			String passwd, String cpf, String telefone, String rua,
			String numero, String cep, Double credito)
			throws ClienteJaExistenteException {
		return Cliente.adicionarCliente(nome, email, login, passwd, cpf,
				telefone, rua, numero, cep, credito);
	}

	/**
	 * Cria um novo produto
	 * 
	 * @param quantidadeEstoque
	 * @param valorCompra
	 * @param valorVenda
	 * @param nome
	 * @param fabricante
	 * @param dataDeFabricacao
	 * @param categoria
	 * @return
	 * @throws ProdutoJaExistenteException
	 */
	public Produto adicionaProduto(int quantidadeEstoque, double valorCompra,
			double valorVenda, String nome, String fabricante,
			Date dataDeFabricacao, Categoria categoria)
			throws ProdutoJaExistenteException {
		setChanged();
		notifyObservers();
		return Produto.adicionaProduto(quantidadeEstoque, valorCompra,
				valorVenda, nome, fabricante, dataDeFabricacao, categoria);
	}

	public void efetuarCompra(ClienteInterface clienteInterface,
			TreeMap<ProdutoInterface, Integer> treeMap, double total)
			throws CreditoInsuficienteException {
		Cliente.efetuaCompra(clienteInterface, treeMap, total);
		setChanged();
		notifyObservers();
	}

	public boolean enviaEmailEsqueceu(String login) throws RemoteException {
		try {
			Cliente.esqueceuSenha(login);
			return true;
		} catch (ClienteNaoEncontradoException e) {
			return false;
		}
	}

	@Override
	public ClienteInterface updateCliente(String nome, String login,
			String senha, String telefone, String rua, String numero,
			String adicional, String cep, ClienteInterface cliente) {

		ClienteInterface c = null;
		try {
			c = Cliente.updateCliente(nome, login, senha, telefone, rua,
					numero, adicional, cep, cliente);
		} catch (SQLException e) {
			Logger.erro(e.toString());
		}
		setChanged();
		notifyObservers();
		return c;
	}

	@Override
	public void addObserver(Observer o) {
		super.addObserver(o);
	}

	@Override
	public int getQuantidadeByCategoriaFabricante(
			Comparator<ProdutoInterface> comparator, int primeiro,
			int quantidade, Categoria cat, String fabricante)
			throws RemoteException {
		return Produto.getQuantidadeByCategoriaFabricante(comparator, primeiro,
				quantidade, cat, fabricante);
	}

	@Override
	public int getQuantidadeByNome(Comparator<ProdutoInterface> c,
			int primeiro, int quantidade, String nome) throws RemoteException {
		return Produto.getQuantidadeByNome(c, primeiro, quantidade, nome);
	}

}
